Skip to main content

core/iter/adapters/
step_by.rs

1use crate::intrinsics;
2use crate::iter::{TrustedLen, TrustedRandomAccess, from_fn};
3use crate::num::NonZero;
4use crate::ops::{Range, Try};
5use crate::range::RangeIter;
6
7/// An iterator for stepping iterators by a custom amount.
8///
9/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
10/// its documentation for more.
11///
12/// [`step_by`]: Iterator::step_by
13/// [`Iterator`]: trait.Iterator.html
14#[must_use = "iterators are lazy and do nothing unless consumed"]
15#[stable(feature = "iterator_step_by", since = "1.28.0")]
16#[derive(Clone, Debug)]
17pub struct StepBy<I> {
18    /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup`
19    /// in the constructor.
20    /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy
21    /// which means the inner iterator cannot be returned to user code.
22    /// Additionally this type-dependent preprocessing means specialized implementations
23    /// cannot be used interchangeably.
24    iter: I,
25    /// This field is `step - 1`, aka the correct amount to pass to `nth` when iterating.
26    /// It MUST NOT be `usize::MAX`, as `unsafe` code depends on being able to add one
27    /// without the risk of overflow.  (This is important so that length calculations
28    /// don't need to check for division-by-zero, for example.)
29    step_minus_one: usize,
30    first_take: bool,
31}
32
33impl<I> StepBy<I> {
34    #[inline]
35    pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
36        assert!(step != 0);
37        let iter = <I as SpecRangeSetup<I>>::setup(iter, step);
38        StepBy { iter, step_minus_one: step - 1, first_take: true }
39    }
40
41    /// The `step` that was originally passed to `Iterator::step_by(step)`,
42    /// aka `self.step_minus_one + 1`.
43    #[inline]
44    fn original_step(&self) -> NonZero<usize> {
45        // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which
46        // means the addition cannot overflow and the result cannot be zero.
47        unsafe { NonZero::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) }
48    }
49}
50
51#[stable(feature = "iterator_step_by", since = "1.28.0")]
52impl<I> Iterator for StepBy<I>
53where
54    I: Iterator,
55{
56    type Item = I::Item;
57
58    #[inline]
59    fn next(&mut self) -> Option<Self::Item> {
60        self.spec_next()
61    }
62
63    #[inline]
64    fn size_hint(&self) -> (usize, Option<usize>) {
65        self.spec_size_hint()
66    }
67
68    #[inline]
69    fn nth(&mut self, n: usize) -> Option<Self::Item> {
70        self.spec_nth(n)
71    }
72
73    fn try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
74    where
75        F: FnMut(Acc, Self::Item) -> R,
76        R: Try<Output = Acc>,
77    {
78        self.spec_try_fold(acc, f)
79    }
80
81    #[inline]
82    fn fold<Acc, F>(self, acc: Acc, f: F) -> Acc
83    where
84        F: FnMut(Acc, Self::Item) -> Acc,
85    {
86        self.spec_fold(acc, f)
87    }
88}
89
90impl<I> StepBy<I>
91where
92    I: ExactSizeIterator,
93{
94    // The zero-based index starting from the end of the iterator of the
95    // last element. Used in the `DoubleEndedIterator` implementation.
96    fn next_back_index(&self) -> usize {
97        let rem = self.iter.len() % self.original_step();
98        if self.first_take { if rem == 0 { self.step_minus_one } else { rem - 1 } } else { rem }
99    }
100}
101
102#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
103impl<I> DoubleEndedIterator for StepBy<I>
104where
105    I: DoubleEndedIterator + ExactSizeIterator,
106{
107    #[inline]
108    fn next_back(&mut self) -> Option<Self::Item> {
109        self.spec_next_back()
110    }
111
112    #[inline]
113    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
114        self.spec_nth_back(n)
115    }
116
117    fn try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
118    where
119        F: FnMut(Acc, Self::Item) -> R,
120        R: Try<Output = Acc>,
121    {
122        self.spec_try_rfold(init, f)
123    }
124
125    #[inline]
126    fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
127    where
128        Self: Sized,
129        F: FnMut(Acc, Self::Item) -> Acc,
130    {
131        self.spec_rfold(init, f)
132    }
133}
134
135// StepBy can only make the iterator shorter, so the len will still fit.
136#[stable(feature = "iterator_step_by", since = "1.28.0")]
137impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
138
139// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
140// These requirements can only be satisfied when the upper bound of the inner iterator's upper
141// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
142// I: TrustedLen would not.
143// This also covers the Range specializations since the ranges also implement TRA
144#[unstable(feature = "trusted_len", issue = "37572")]
145unsafe impl<I> TrustedLen for StepBy<I> where I: Iterator + TrustedRandomAccess {}
146
147trait SpecRangeSetup<T> {
148    fn setup(inner: T, step: usize) -> T;
149}
150
151impl<T> SpecRangeSetup<T> for T {
152    #[inline]
153    default fn setup(inner: T, _step: usize) -> T {
154        inner
155    }
156}
157
158/// Specialization trait to optimize `StepBy<Range<{integer}>>` iteration.
159///
160/// # Safety
161///
162/// Technically this is safe to implement (look ma, no unsafe!), but in reality
163/// a lot of unsafe code relies on ranges over integers being correct.
164///
165/// For correctness *all* public StepBy methods must be specialized
166/// because `setup` drastically alters the meaning of the struct fields so that mixing
167/// different implementations would lead to incorrect results.
168unsafe trait StepByImpl<I> {
169    type Item;
170
171    fn spec_next(&mut self) -> Option<Self::Item>;
172
173    fn spec_size_hint(&self) -> (usize, Option<usize>);
174
175    fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
176
177    fn spec_try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
178    where
179        F: FnMut(Acc, Self::Item) -> R,
180        R: Try<Output = Acc>;
181
182    fn spec_fold<Acc, F>(self, acc: Acc, f: F) -> Acc
183    where
184        F: FnMut(Acc, Self::Item) -> Acc;
185}
186
187/// Specialization trait for double-ended iteration.
188///
189/// See also: `StepByImpl`
190///
191/// # Safety
192///
193/// The specializations must be implemented together with `StepByImpl`
194/// where applicable. I.e. if `StepBy` does support backwards iteration
195/// for a given iterator and that is specialized for forward iteration then
196/// it must also be specialized for backwards iteration.
197unsafe trait StepByBackImpl<I> {
198    type Item;
199
200    fn spec_next_back(&mut self) -> Option<Self::Item>
201    where
202        I: DoubleEndedIterator + ExactSizeIterator;
203
204    fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
205    where
206        I: DoubleEndedIterator + ExactSizeIterator;
207
208    fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
209    where
210        I: DoubleEndedIterator + ExactSizeIterator,
211        F: FnMut(Acc, Self::Item) -> R,
212        R: Try<Output = Acc>;
213
214    fn spec_rfold<Acc, F>(self, init: Acc, f: F) -> Acc
215    where
216        I: DoubleEndedIterator + ExactSizeIterator,
217        F: FnMut(Acc, Self::Item) -> Acc;
218}
219
220unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
221    type Item = I::Item;
222
223    #[inline]
224    default fn spec_next(&mut self) -> Option<I::Item> {
225        let step_size = if self.first_take { 0 } else { self.step_minus_one };
226        self.first_take = false;
227        self.iter.nth(step_size)
228    }
229
230    #[inline]
231    default fn spec_size_hint(&self) -> (usize, Option<usize>) {
232        #[inline]
233        fn first_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
234            move |n| if n == 0 { 0 } else { 1 + (n - 1) / step }
235        }
236
237        #[inline]
238        fn other_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
239            move |n| n / step
240        }
241
242        let (low, high) = self.iter.size_hint();
243
244        if self.first_take {
245            let f = first_size(self.original_step());
246            (f(low), high.map(f))
247        } else {
248            let f = other_size(self.original_step());
249            (f(low), high.map(f))
250        }
251    }
252
253    #[inline]
254    default fn spec_nth(&mut self, mut n: usize) -> Option<I::Item> {
255        if self.first_take {
256            self.first_take = false;
257            let first = self.iter.next();
258            if n == 0 {
259                return first;
260            }
261            n -= 1;
262        }
263        // n and self.step_minus_one are indices, we need to add 1 to get the amount of elements
264        // When calling `.nth`, we need to subtract 1 again to convert back to an index
265        let mut step = self.original_step().get();
266        // n + 1 could overflow
267        // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
268        if n == usize::MAX {
269            self.iter.nth(step - 1);
270        } else {
271            n += 1;
272        }
273
274        // overflow handling
275        loop {
276            let mul = n.checked_mul(step);
277            {
278                if intrinsics::likely(mul.is_some()) {
279                    return self.iter.nth(mul.unwrap() - 1);
280                }
281            }
282            let div_n = usize::MAX / n;
283            let div_step = usize::MAX / step;
284            let nth_n = div_n * n;
285            let nth_step = div_step * step;
286            let nth = if nth_n > nth_step {
287                step -= div_n;
288                nth_n
289            } else {
290                n -= div_step;
291                nth_step
292            };
293            self.iter.nth(nth - 1);
294        }
295    }
296
297    default fn spec_try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
298    where
299        F: FnMut(Acc, Self::Item) -> R,
300        R: Try<Output = Acc>,
301    {
302        #[inline]
303        fn nth<I: Iterator>(
304            iter: &mut I,
305            step_minus_one: usize,
306        ) -> impl FnMut() -> Option<I::Item> + '_ {
307            move || iter.nth(step_minus_one)
308        }
309
310        if self.first_take {
311            self.first_take = false;
312            match self.iter.next() {
313                None => return try { acc },
314                Some(x) => acc = f(acc, x)?,
315            }
316        }
317        from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
318    }
319
320    default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
321    where
322        F: FnMut(Acc, Self::Item) -> Acc,
323    {
324        #[inline]
325        fn nth<I: Iterator>(
326            iter: &mut I,
327            step_minus_one: usize,
328        ) -> impl FnMut() -> Option<I::Item> + '_ {
329            move || iter.nth(step_minus_one)
330        }
331
332        if self.first_take {
333            self.first_take = false;
334            match self.iter.next() {
335                None => return acc,
336                Some(x) => acc = f(acc, x),
337            }
338        }
339        from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f)
340    }
341}
342
343unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I> {
344    type Item = I::Item;
345
346    #[inline]
347    default fn spec_next_back(&mut self) -> Option<Self::Item> {
348        self.iter.nth_back(self.next_back_index())
349    }
350
351    #[inline]
352    default fn spec_nth_back(&mut self, n: usize) -> Option<I::Item> {
353        // `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
354        // is out of bounds because the length of `self.iter` does not exceed
355        // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
356        // zero-indexed
357        let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index());
358        self.iter.nth_back(n)
359    }
360
361    default fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
362    where
363        F: FnMut(Acc, Self::Item) -> R,
364        R: Try<Output = Acc>,
365    {
366        #[inline]
367        fn nth_back<I: DoubleEndedIterator>(
368            iter: &mut I,
369            step_minus_one: usize,
370        ) -> impl FnMut() -> Option<I::Item> + '_ {
371            move || iter.nth_back(step_minus_one)
372        }
373
374        match self.next_back() {
375            None => try { init },
376            Some(x) => {
377                let acc = f(init, x)?;
378                from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
379            }
380        }
381    }
382
383    #[inline]
384    default fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
385    where
386        Self: Sized,
387        F: FnMut(Acc, I::Item) -> Acc,
388    {
389        #[inline]
390        fn nth_back<I: DoubleEndedIterator>(
391            iter: &mut I,
392            step_minus_one: usize,
393        ) -> impl FnMut() -> Option<I::Item> + '_ {
394            move || iter.nth_back(step_minus_one)
395        }
396
397        match self.next_back() {
398            None => init,
399            Some(x) => {
400                let acc = f(init, x);
401                from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f)
402            }
403        }
404    }
405}
406
407/// For these implementations, `SpecRangeSetup` calculates the number
408/// of iterations that will be needed and stores that in `iter.end`.
409///
410/// The various iterator implementations then rely on that to not need
411/// overflow checking, letting loops just be counted instead.
412///
413/// These only work for unsigned types, and will need to be reworked
414/// if you want to use it to specialize on signed types.
415///
416/// Currently these are only implemented for integers up to `usize` due to
417/// correctness issues around `ExactSizeIterator` impls on 16bit platforms.
418/// And since `ExactSizeIterator` is a prerequisite for backwards iteration
419/// and we must consistently specialize backwards and forwards iteration
420/// that makes the situation complicated enough that it's not covered
421/// for now.
422///
423/// After `SpecRangeSetup::setup`, both `Range<T>` and its new-range wrapper
424/// `RangeIter<T>` carry the cursor and countdown in the same underlying legacy
425/// `Range`. This accessor exposes that shared range so one specialization can
426/// serve both: it is an identity for `Range<T>` and unwraps the newtype for
427/// `RangeIter<T>`, so it compiles away.
428trait AsLegacyRange<T> {
429    fn as_legacy_range(&self) -> &Range<T>;
430    fn as_legacy_range_mut(&mut self) -> &mut Range<T>;
431}
432
433impl<T> AsLegacyRange<T> for Range<T> {
434    #[inline]
435    fn as_legacy_range(&self) -> &Range<T> {
436        self
437    }
438    #[inline]
439    fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
440        self
441    }
442}
443
444impl<T> AsLegacyRange<T> for RangeIter<T> {
445    #[inline]
446    fn as_legacy_range(&self) -> &Range<T> {
447        &self.0
448    }
449    #[inline]
450    fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
451        &mut self.0
452    }
453}
454
455macro_rules! spec_int_ranges {
456    ($ctor:ident; $($t:ty)*) => ($(
457
458        const _: () = assert!(usize::BITS >= <$t>::BITS);
459
460        impl SpecRangeSetup<$ctor<$t>> for $ctor<$t> {
461            #[inline]
462            fn setup(mut r: $ctor<$t>, step: usize) -> $ctor<$t> {
463                let inner_len = r.size_hint().0;
464                // If step exceeds $t::MAX, then the count will be at most 1 and
465                // thus always fit into $t.
466                let yield_count = inner_len.div_ceil(step);
467                // Turn the range end into an iteration counter
468                r.as_legacy_range_mut().end = yield_count as $t;
469                r
470            }
471        }
472
473        unsafe impl StepByImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
474            #[inline]
475            fn spec_next(&mut self) -> Option<$t> {
476                // if a step size larger than the type has been specified fall back to
477                // t::MAX, in which case remaining will be at most 1.
478                let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
479                let r = self.iter.as_legacy_range_mut();
480                let remaining = r.end;
481                if remaining > 0 {
482                    let val = r.start;
483                    // this can only overflow during the last step, after which the value
484                    // will not be used
485                    r.start = val.wrapping_add(step);
486                    r.end = remaining - 1;
487                    Some(val)
488                } else {
489                    None
490                }
491            }
492
493            #[inline]
494            fn spec_size_hint(&self) -> (usize, Option<usize>) {
495                let remaining = self.iter.as_legacy_range().end as usize;
496                (remaining, Some(remaining))
497            }
498
499            // The methods below are all copied from the Iterator trait default impls.
500            // We have to repeat them here so that the specialization overrides the StepByImpl defaults
501
502            #[inline]
503            fn spec_nth(&mut self, n: usize) -> Option<Self::Item> {
504                self.advance_by(n).ok()?;
505                self.next()
506            }
507
508            #[inline]
509            fn spec_try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
510                where
511                    F: FnMut(Acc, Self::Item) -> R,
512                    R: Try<Output = Acc>
513            {
514                let mut accum = init;
515                while let Some(x) = self.next() {
516                    accum = f(accum, x)?;
517                }
518                try { accum }
519            }
520
521            #[inline]
522            fn spec_fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
523                where
524                    F: FnMut(Acc, Self::Item) -> Acc
525            {
526                // if a step size larger than the type has been specified fall back to
527                // t::MAX, in which case remaining will be at most 1.
528                let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
529                let r = self.iter.as_legacy_range();
530                let remaining = r.end;
531                let mut acc = init;
532                let mut val = r.start;
533                for _ in 0..remaining {
534                    acc = f(acc, val);
535                    // this can only overflow during the last step, after which the value
536                    // will no longer be used
537                    val = val.wrapping_add(step);
538                }
539                acc
540            }
541        }
542    )*)
543}
544
545macro_rules! spec_int_ranges_r {
546    ($ctor:ident; $($t:ty)*) => ($(
547        const _: () = assert!(usize::BITS >= <$t>::BITS);
548
549        unsafe impl StepByBackImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
550
551            #[inline]
552            fn spec_next_back(&mut self) -> Option<Self::Item> {
553                let step = self.original_step().get() as $t;
554                let r = self.iter.as_legacy_range_mut();
555                let remaining = r.end;
556                if remaining > 0 {
557                    let start = r.start;
558                    r.end = remaining - 1;
559                    Some(start + step * (remaining - 1))
560                } else {
561                    None
562                }
563            }
564
565            // The methods below are all copied from the Iterator trait default impls.
566            // We have to repeat them here so that the specialization overrides the StepByImplBack defaults
567
568            #[inline]
569            fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> {
570                if self.advance_back_by(n).is_err() {
571                    return None;
572                }
573                self.next_back()
574            }
575
576            #[inline]
577            fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
578            where
579                F: FnMut(Acc, Self::Item) -> R,
580                R: Try<Output = Acc>
581            {
582                let mut accum = init;
583                while let Some(x) = self.next_back() {
584                    accum = f(accum, x)?;
585                }
586                try { accum }
587            }
588
589            #[inline]
590            fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
591            where
592                F: FnMut(Acc, Self::Item) -> Acc
593            {
594                let mut accum = init;
595                while let Some(x) = self.next_back() {
596                    accum = f(accum, x);
597                }
598                accum
599            }
600        }
601    )*)
602}
603
604// The same specialization covers `Range<{integer}>` and the new-range iterator
605// `RangeIter<{integer}>`, which wraps a `Range` (see `AsLegacyRange`).
606//
607// The backward (`_r`) specialization requires `ExactSizeIterator`. `RangeIter`
608// implements it only for `usize`/`u8`/`u16` (see `range_exact_iter_impl!` in
609// `range::iter`), narrower than `Range`, so `RangeIter`'s backward set omits
610// `u32` even where `Range` includes it; `Range<u64>` is likewise omitted on
611// 64-bit since its length can exceed `usize`.
612#[cfg(target_pointer_width = "64")]
613mod step_by_spec {
614    use super::*;
615    spec_int_ranges!(Range; u8 u16 u32 u64 usize);
616    spec_int_ranges!(RangeIter; u8 u16 u32 u64 usize);
617    spec_int_ranges_r!(Range; u8 u16 u32 usize);
618    spec_int_ranges_r!(RangeIter; u8 u16 usize);
619}
620
621#[cfg(target_pointer_width = "32")]
622mod step_by_spec {
623    use super::*;
624    spec_int_ranges!(Range; u8 u16 u32 usize);
625    spec_int_ranges!(RangeIter; u8 u16 u32 usize);
626    spec_int_ranges_r!(Range; u8 u16 u32 usize);
627    spec_int_ranges_r!(RangeIter; u8 u16 usize);
628}
629
630#[cfg(target_pointer_width = "16")]
631mod step_by_spec {
632    use super::*;
633    spec_int_ranges!(Range; u8 u16 usize);
634    spec_int_ranges!(RangeIter; u8 u16 usize);
635    spec_int_ranges_r!(Range; u8 u16 usize);
636    spec_int_ranges_r!(RangeIter; u8 u16 usize);
637}